﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test.Compare
{
    /// <summary>
    /// 标识类型的基类
    /// </summary>
    /// <typeparam name="T">标识值的类型</typeparam>
    public abstract class FlagBase<T>
    {
        #region 实例成员

        /// <summary>
        /// 私有的实际值
        /// </summary>
        protected readonly T value;

        /// <summary>
        /// 标识的实际值
        /// </summary>
        public T Value { get { return value; } }

        /// <summary>
        /// 私有的序号
        /// </summary>
        protected readonly int serialNumber;

        /// <summary>
        /// 序列号，用来排序
        /// </summary>
        protected internal int SerialNumber { get { return serialNumber; } }

        #endregion

        #region Ctor

        protected FlagBase(T value, int serialNumber = int.MaxValue)
        {
            if (value == null)
                throw new ArgumentNullException("value");

            this.value = value;
            this.serialNumber = serialNumber;
        }

        #endregion

        #region 重写方法

        public override bool Equals(object obj)
        {
            /*
             * 因为同一个标识在内存中只存在一个对象，所以直接比较引用就可以，又快又简单
             * 但是注意，假如obj对象是T类型，这个方法会返回false，这是符合CLR对Equals方法的设计的。
             */
            return Object.ReferenceEquals(this, obj);
        }

        public override int GetHashCode()
        {
            return this.value.GetHashCode();
        }

        public override string ToString()
        {
            return value.ToString();
        }

        #endregion

        #region 单向隐式转换成值的类型

        /// <summary>
        /// 隐式转换成值的类型
        /// </summary>
        /// <param name="flag">标识对象</param>
        /// <returns>标识值，如果标识为空就返回标识值类型的默认值</returns>
        public static implicit operator T(FlagBase<T> flag)
        {
            return flag == null ? default(T) : flag.value;
        }

        #endregion

    }

    /// <summary>
    /// 标识的管理类，提供相关的管理功能
    /// </summary>
    /// <typeparam name="TFlag">标识的类型</typeparam>
    /// <typeparam name="TValue">标识值的类型</typeparam>
    public abstract class FlagManager<TFlag, TValue> where TFlag : FlagBase<TValue>
    {
        #region 数据成员
        /// <summary>
        /// 默认值,有可能为空，取决于具体标识的设置
        /// </summary>
        public TFlag DefaultFlag { get; private set; }

        /// <summary>
        /// 标识值和标识的映射关系
        /// </summary>
        private readonly Dictionary<TValue, TFlag> FlagMap = new Dictionary<TValue, TFlag>();
        #endregion

        #region ctor

        protected FlagManager()
        {
            Type flagtype = typeof(TFlag);

            var fields = flagtype.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);

            if (fields != null)
            {
                Type attrtype = typeof(DefaultFlagAttribute);

                foreach (var item in fields)
                {
                    if (item.FieldType != flagtype)
                        continue;

                    TFlag flag = item.GetValue(null) as TFlag;
                    if (flag == null)
                        continue;

                    FlagMap.Add(flag.Value, flag);

                    if (Attribute.IsDefined(item, attrtype))
                    {
                        this.DefaultFlag = flag;
                    }
                }
            }
        }

        #endregion

        #region 公开方法
        /// <summary>
        /// 获取此类型所有的标记。
        /// </summary>
        /// <returns></returns>
        public List<TFlag> GetAllFlag()
        {
            return FlagMap.Values.ToList();
        }

        /// <summary>
        /// 获取此类型所有的标记,按照序号排序。
        /// </summary>
        /// <returns></returns>
        public List<TFlag> GetSortedAllFlag()
        {
            return FlagMap.Values.OrderBy(x => x.SerialNumber).ToList();
        }

        /// <summary>
        /// 获取指定值的标记
        /// </summary>
        /// <param name="flag">值</param>
        /// <returns>标记，如果不合法则为null</returns>
        public TFlag GetFlag(TValue value)
        {
            if (value == null)
                return null;

            TFlag result;

            if (FlagMap.TryGetValue(value, out result))
            {
                return result;
            }

            return null;
        }

        /// <summary>
        /// 获取与指定的值相关联的标志值。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="flag"></param>
        /// <returns></returns>
        public bool TryGetFlag(TValue value, out TFlag flag)
        {
            if (value == null)
            {
                flag = null;
                return false;
            }

            return FlagMap.TryGetValue(value, out flag);
        }

        /// <summary>
        /// 检查是否有指定值的标识
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool IsDefined(TValue value)
        {
            if (value == null)
                return false;

            return FlagMap.ContainsKey(value);
        }
        #endregion
    }

    /// <summary>
    /// 标明默认标识的Attribute
    /// </summary>
    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
    public sealed class DefaultFlagAttribute : Attribute
    {
        public DefaultFlagAttribute()
        { }
    }
}
